package com.staplehurst.pull.refresh;

import java.text.SimpleDateFormat;
import java.util.Calendar;

import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.AbsListView.OnScrollListener;
import android.widget.TextView;

import com.staplehurst.pull.refresh.R;

public class PullableList extends ListView implements ListView.OnScrollListener {

	// Hard-coded value, may need to change for different pixel densities.
	private static final int PIXELS_FROM_TOP = -8;

	private RelativeLayout mRefreshHeader;
	private TextView mRefreshViewText;
	private TextView mRefreshTimeText;
	private ImageView mRefreshViewImage;
	private ProgressBar mProgressBar;
	private static final String TAG = "PullableList";
	private boolean mHeaderVisible = false;
	private boolean mArrowFlipped = false;
	private boolean mReleaseMode = false;
	private boolean mUpdating = false;
	private RotateAnimation mArrowFlip;
	private RotateAnimation mReverseArrowFlip;
	private OnScrollListener mOnScrollListener;
	private PullUpdateListener pullUpdateListener;
	private int mHeaderTop = 0;

	@Override
	public void setOnScrollListener(AbsListView.OnScrollListener l) {
		mOnScrollListener = l;
	}

	public PullableList(Context context) {
		super(context);
	}

	public PullableList(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public PullableList(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public PullableList(Context context, int backgroundColor, int arrowColor, 
			int refreshTextColor, int refreshTimeColor) {		
		super(context);
		setHeader(context);
		setHeaderBackgroundColor(backgroundColor);	
	}

	public void setHeaderBackgroundColor(int Color) {
		mRefreshHeader.setBackgroundColor(Color);
	}

	public void setHeaderArrowColor(int Color) {		
		mRefreshViewImage.setColorFilter(Color, Mode.SRC_ATOP);	
	}

	public void setHeaderRefreshTextColor(int Color) {
		mRefreshViewText.setTextColor(Color);
	}

	public void setHeaderRefreshTimeColor(int Color) {
		mRefreshTimeText.setTextColor(Color);
	}


	public void setHeader(Context context) {

		mArrowFlip = new RotateAnimation(0, -180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mArrowFlip.setInterpolator(new LinearInterpolator());
		mArrowFlip.setDuration(350);
		mArrowFlip.setFillAfter(true);

		mReverseArrowFlip = new RotateAnimation(-180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mReverseArrowFlip.setInterpolator(new LinearInterpolator());
		mReverseArrowFlip.setDuration(350);
		mReverseArrowFlip.setFillAfter(true);

		mRefreshHeader = new RelativeLayout(context);
		mRefreshHeader.setPadding(0, 20, 0, 20);
		mRefreshHeader.setBackgroundResource(R.drawable.pull_to_refresh_header_background);

		mRefreshViewText = new TextView(context);
		mRefreshViewText.setId(2);
		mRefreshViewText.setTextColor(Color.BLACK);
		mRefreshViewText.setTextSize(15);
		mRefreshViewText.setText("Pull down to refresh...");
		RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		lp2.addRule(RelativeLayout.CENTER_HORIZONTAL);
		mRefreshHeader.addView(mRefreshViewText, lp2);

		mRefreshTimeText = new TextView(context);
		mRefreshTimeText.setId(3);
		mRefreshTimeText.setText(returnLastUpdate());
		mRefreshTimeText.setTextColor(Color.BLACK);
		mRefreshTimeText.setTextSize(10);
		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		lp.addRule(RelativeLayout.BELOW, mRefreshViewText.getId());
		lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
		mRefreshHeader.addView(mRefreshTimeText, lp);

		mRefreshViewImage = new ImageView(context);
		mRefreshViewImage.setId(1);
		mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);

		RelativeLayout.LayoutParams lp0 = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		lp0.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		lp0.addRule(RelativeLayout.CENTER_VERTICAL);
		lp0.leftMargin = 60;
		mRefreshHeader.addView(mRefreshViewImage, lp0);

		String ver = Build.VERSION.SDK;

		if (Integer.parseInt(ver) > 4) {
			mProgressBar = new ProgressBar(context, null,
					android.R.attr.progressBarStyleSmallInverse);
		}
		else {
			mProgressBar = new ProgressBar(context, null,
					android.R.attr.progressBarStyleSmall);
		}

		mProgressBar.setId(4);
		RelativeLayout.LayoutParams lpbar = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		lpbar.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		lpbar.addRule(RelativeLayout.CENTER_VERTICAL);
		lpbar.leftMargin = 60;
		mRefreshHeader.addView(mProgressBar, lpbar);
		mProgressBar.setVisibility(View.GONE);

		addHeaderView(mRefreshHeader, null, false);
		super.setOnScrollListener(this);

	}

	public String returnLastUpdate() {		
		StringBuilder sb = new StringBuilder();
		sb.append("Last Updated: ");
		Calendar c = Calendar.getInstance();
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String formattedDate = df.format(c.getTime());
		sb.append(formattedDate);
		return sb.toString();		
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
		setSelection(2);
		//	    setSelectionAfterHeaderView();
	}

	int down_y = 0;
	long down_time;
	long up_time;
	long time_delta = 0;

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		final int y = (int) event.getY();		  
		mHeaderTop = mRefreshHeader.getTop();

		switch (event.getAction()) {
		case MotionEvent.ACTION_UP:	            	
			up_time = event.getEventTime();
			time_delta = up_time - down_time;

			if (mReleaseMode && time_delta > 300) {
				mRefreshViewImage.setVisibility(View.INVISIBLE);
				mRefreshViewImage.setImageDrawable(null);
				mUpdating = true;
				mProgressBar.setVisibility(View.VISIBLE);
				mRefreshViewText.setText("Updating...");
				mUpdating = true;
				pullUpdateListener.onUpdateList();	            		
			}
			break;
		case MotionEvent.ACTION_DOWN:	            	
			down_y = y;
			down_time = event.getEventTime();
			break;
		case MotionEvent.ACTION_MOVE:
			//	            	time_delta = up_time - down_time;
			if ((y - down_y) > 20) {

				if (mHeaderVisible && mHeaderTop > PIXELS_FROM_TOP) {
					mRefreshViewText.setText("Release to refresh...");
					mReleaseMode = true;
					if (!mArrowFlipped) {
						mRefreshViewImage.clearAnimation();
						mRefreshViewImage.startAnimation(mArrowFlip);
						mArrowFlipped = true;
					}
				}
				else if (mHeaderVisible) {
					mRefreshViewText.setText("Pull down to refresh...");
					mReleaseMode = false;
					if (mArrowFlipped && !mUpdating) {
						mRefreshViewImage.clearAnimation();
						mRefreshViewImage.startAnimation(mReverseArrowFlip);
						mArrowFlipped = false;
					}
				}
			}
			break;
		}
		return super.onTouchEvent(event);
	}  	  

	private void resetHeader() {
		mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);
		mRefreshViewImage.setVisibility(View.VISIBLE);
		mRefreshViewText.setText("Pull down to refresh...");
		if (mArrowFlipped) {
			mRefreshViewImage.clearAnimation();
			mRefreshViewImage.startAnimation(mReverseArrowFlip);
			mArrowFlipped = false;
			mReleaseMode = false;
		}
		setSelection(1);
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {

		if (firstVisibleItem == 0) {
			mHeaderVisible = true;
		}
		else {			
			if (mHeaderVisible) {
				mHeaderVisible = false;
				resetHeader();
			}
		}

	}

	/*
	 * Don't really use the ScrollState. It might be useful for detecting a Fling scroll
	 * so that we can keep the selection at 1 instead of displaying the header...
	 * 
	 * Keeping the method in as a placeholder.
	 * 
	 */

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		// TODO Auto-generated method stub		
		switch (scrollState) {
		case OnScrollListener.SCROLL_STATE_IDLE:
			break;
		case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
			break;
		case OnScrollListener.SCROLL_STATE_FLING:
			break;
		}		
	}

	public void updateComplete() {        
		mUpdating = false;
		mRefreshTimeText.setText(returnLastUpdate());
		mProgressBar.setVisibility(View.GONE);
		resetHeader();
	}

	/*
	 * The simple callback Interface.
	 */

	static public interface PullUpdateListener {
		public void onUpdateList();
	}

	public void setPullUpdateListener(PullUpdateListener pullUpdateListener) {
		this.pullUpdateListener = pullUpdateListener;
	}

}